package com.base.web.core.config.shiro;

import com.base.web.core.common.BaseConstant;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Map;


/**
 * Created with IntelliJ IDEA.
 * Description: shiro 配置类
 *   ConditionalOnProperty 根据配置文件中的条件决定该配置类是否生效
 * @Author: RENTIE
 * Date: 2018-07-04 14:06
 */
@Configuration
@ConditionalOnProperty(name = "shiro-filter.use", havingValue = "true")
public class ShiroConfig {

    /**
     * 获取配置文件的拦截过滤配置
     *
     * @return
     */
    @Bean
    @ConfigurationProperties(prefix = "shiro-filter")
    public ShiroFilters initFilters() {
        return new ShiroFilters();
    }

    /**
     * 记住我：自动登录-1
     */
    @Bean
    public SimpleCookie getSimpleCookie() {
        SimpleCookie simpleCookie = new SimpleCookie();
        simpleCookie.setName("rememberMe");
        //7天 单位秒
        simpleCookie.setMaxAge(BaseConstant.SHIRO_COOKIE_AGE);
        return simpleCookie;
    }

    /**
     * 记住我：自动登录-2
     */
    @Bean
    public CookieRememberMeManager getCookieRememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(getSimpleCookie());
        //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
        cookieRememberMeManager.setCipherKey(Base64.decode("2AvVhdsods0FSA3SDFAdag=="));

        return cookieRememberMeManager;
    }

    /**
     * 开启MD5加密
     *
     * @return
     */
    @Bean
    public HashedCredentialsMatcher getMatcher() {
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        //加密算法
        matcher.setHashAlgorithmName("md5");
        //加密次数
        matcher.setHashIterations(BaseConstant.MD5_HASHITERATIONS);
        return matcher;
    }

    /**
     * 自定义Realm密码验证与加密
     *
     * @return
     */
    @Bean
    public CustomRealm getCustomRealm() {
        CustomRealm customRealm = new CustomRealm();
        customRealm.setCredentialsMatcher(getMatcher());
        return customRealm;
    }

    /**
     * 创建SecurityManager环境
     *
     * @return
     */
    @Bean
    public SecurityManager getSecurityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(getCustomRealm());
        securityManager.setRememberMeManager(getCookieRememberMeManager());
        return securityManager;
    }

    /**
     * Shiro在Web项目中的过滤
     *
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean getfilterFactoryBean() {
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
        filterFactoryBean.setSecurityManager(getSecurityManager());

        //默认跳转到登陆页面
        filterFactoryBean.setLoginUrl("/login");
        //登陆成功后的页面
        filterFactoryBean.setSuccessUrl("/index");
        //未认证跳转页面
        filterFactoryBean.setUnauthorizedUrl("/403");


        /**
         *  只有在下面配置路径访问权限，Shiro才会执行自动跳转。
         *  如果使用Shiro注解权限，就只会报异常，
         *  就只能采用统一异常处理的方法。
         */
        //拦截器.
        Map<String, String> filterChainDefinitionMap = initFilters().getFilterMap();


//        //登出操作
//        filterChainDefinitionMap.put("/logout", "logout");
//
//        // 匿名访问登录链接
//        filterChainDefinitionMap.put("/dologin", "anon");
//
//        // 匿名访问验证码链接
//        filterChainDefinitionMap.put("/captcha/*", "anon");
//
//        // 匿名访问静态资源
//        filterChainDefinitionMap.put("/css/**", "anon");
//        filterChainDefinitionMap.put("/js/**", "anon");
//        filterChainDefinitionMap.put("/img/**", "anon");
//        filterChainDefinitionMap.put("/layui/**", "anon");
//
//        //需要认证的url
//        filterChainDefinitionMap.put("/**", "authc");

        filterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return filterFactoryBean;
    }


    /**
     * 保证Shiro的声明周期
     *
     * @return
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 开启shiro aop注解支持.
     * 使用代理方式;所以需要开启代码支持;否则@RequiresRoles等注解无法生效
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}
